﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Maps.MapControl;
using System.Collections.Generic;

namespace SilverlightMapCreator
{
    public static class GeoMath
    {
        /// <summary>
        /// Converts degrees to radians. Used to convert the latitude and longitude coordinates.
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static double ToRad(double angle)
        {
            var r = angle * Math.PI / 180;
            return r;
        }



        /// <summary>
        /// Returns distsance in meters between two points of earth using the Spherical Law of Cosines
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static int ComputeDistance(Location start, Location end)
        {

            //return Harvesine(start, end);
            //return Pythagoras(start, end);
            return SphericalEarthProjectedToAPlane(start, end);

            //Debug.WriteLine("Harvesine: " + d1 + " - " + harvtime + " sphere: " + d2 + " - " + spheretiem);
        }

        public static int Pythagoras(Location start, Location end)
        {
            var R = 6371000;
            double lat1 = ToRad(start.Latitude);
            double lat2 = ToRad(end.Latitude);

            double lng1 = ToRad(start.Longitude);
            double lng2 = ToRad(end.Longitude);

            double dlng = lng2 - lng1;
            double dlat = lat2 - lat1;

            int d = (int)(R * Math.Sqrt(dlat * dlat + dlng * dlng));
            return d;
        }

        public static int Harvesine(Location start, Location end)
        {
            double lat1 = ToRad(start.Latitude);
            double lat2 = ToRad(end.Latitude);

            double lng1 = ToRad(start.Longitude);
            double lng2 = ToRad(end.Longitude);

            var R = 6371000; // m

            double dlng = lng2 - lng1;
            double dlat = lat2 - lat1;

            var a = Math.Pow(Math.Sin(dlat / 2), 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Pow(Math.Sin(dlng / 2), 2);
            var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));

            var d = R * c;

            //harvesine formula

            /* Law of cosines
            var d = Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) +
                              Math.Cos(lat1) * Math.Cos(lat2) *
                              Math.Cos(lng1 - lng2)) * R;
            */
            return (int)d;
        }

        public static int SphericalEarthProjectedToAPlane(Location start, Location end)
        {
            double lat1 = ToRad(start.Latitude);
            double lat2 = ToRad(end.Latitude);

            double lng1 = ToRad(start.Longitude);
            double lng2 = ToRad(end.Longitude);
            var r = 6371000;
            double diflat = lat1 - lat2;
            double diflng = lng1 - lng2;

            double meanLat = (lat1 + lat2) / 2;

            var help = Math.Cos(meanLat) * diflng;
            int d = (int)(r * Math.Sqrt(diflat * diflat + help * help));
            return d;
        }

        public static Segment FindNearestSeg(Location LL, List<Location> routePts)
        {

            Segment s = new Segment();
            double dist = Double.MaxValue;
            double d = 0;
            double t = 0;

            int pos = 0;
            Location pt0 = new Location();
            foreach (Location pt1 in routePts)
            {
                if (pos++ > 0)
                {
                    double XKJ = pt0.Longitude - LL.Longitude;
                    double YKJ = pt0.Latitude - LL.Latitude;
                    double XLK = pt1.Longitude - pt0.Longitude;
                    double YLK = pt1.Latitude - pt0.Latitude;
                    double denom = XLK * XLK + YLK * YLK;
                    if (denom == 0)
                    {
                        d = (XKJ * XKJ + YKJ * YKJ);
                    }
                    else
                    {
                        t = -(XKJ * XLK + YKJ * YLK) / denom;
                        t = Math.Min(Math.Max(t, 0.0), 1.0);
                        double xf = XKJ + t * XLK;
                        double yf = YKJ + t * YLK;
                        d = xf * xf + yf * yf;
                    }
                    if (d < dist)
                    {
                        dist = d;
                        s.nearestPt = new Location(pt0.Latitude + t * YLK, pt0.Longitude + t * XLK);
                        s.linePt1 = new Location(pt0.Latitude, pt0.Longitude);
                        s.linePt2 = new Location(pt1.Latitude, pt1.Longitude);
                        s.distance = dist;
                    }
                }
                pt0 = pt1;
            }

            return s;

        }

        public static double Distance(MyPoint MyPoint1, MyPoint MyPoint2)
        {

            var a = Math.Abs(MyPoint1.X - MyPoint2.X);
            var b = Math.Abs(MyPoint1.Y - MyPoint2.Y);

            var asquare = a * a;
            var bsquare = b * b;
            double distance = Math.Sqrt(asquare + bsquare);
            return distance;
        }
    }
}
